gusucode.com > VC 达内MFC例子集源码-源码程序 > VC 达内MFC例子集源码-源码程序/code/20101228/day02.txt

    一 消息映射
  1 消息映射添加
    1.1 在FrameWnd添加消息宏定义
    		DECLARE_MESSAGE_MAP
    1.2 添加消息宏实现
        BEGIN_MESSAGE_MAP( theClass, parentClass )
				END_MESSAGE_MAP( )
    1.3 添加消息处理函数
				afx_msg LRESULT OnPaint( WPARAM wParam,
					LPARAM lParam );
    1.4 添加消息和处理函数的对应
				ON_MESSAGE( WM_PAINT, OnPaint )
				
	2 消息宏的实现
    2.1 数据类型
      2.1.1 AFX_MSGMAP_ENTRY 是用于保存
      消息ID与对应函数指针,及相关的信息
      struct AFX_MSGMAP_ENTRY
			{
				UINT nMessage; //消息ID
				UINT nCode;//通知代码
				UINT nID; //控件的ID
				UINT nLastID;//控件的ID范围的最后
				UINT nSig;//操作类型或pfn函数类型
				AFX_PMSG pfn;//消息处理函数的函数指针
			};
			2.1.2 AFX_MSGMAP 用于保存GetBaseMap
			 的函数地址及AFX_MSGMAP_ENTRY数组的
			 地址.
			struct AFX_MSGMAP
			{
      	const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
      	//函数指针
      	const AFX_MSGMAP_ENTRY* lpEntries;
      	//AFX_MSGMAP_ENTRY类型指针
      };
		2.2 宏代码
	  class CMsgFrame : public CFrameWnd  
  	{
	  private: 
	  	//保存消息ID和对应的处理函数的数组
			static const AFX_MSGMAP_ENTRY _messageEntries[]; 
		protected: 
		  //保存了CMsgFrame中的_GetBaseMessageMap
		  //函数指针以及_messageEntries数组地址
			static AFX_DATA const AFX_MSGMAP messageMap; 
			static const AFX_MSGMAP* PASCAL _GetBaseMessageMap(); 
			virtual const AFX_MSGMAP* GetMessageMap() const; 
		}
    const AFX_MSGMAP* PASCAL CMsgFrame::_GetBaseMessageMap() 
		{ 
		    return &CFrameWnd::messageMap; 
		} 
		const AFX_MSGMAP* CMsgFrame::GetMessageMap() const 
		{ 
				return &CMsgFrame::messageMap; 
		} 
		
		AFX_COMDAT AFX_DATADEF const AFX_MSGMAP CMsgFrame::messageMap = 
		{		
		  	&CMsgFrame::_GetBaseMessageMap, 
		    &CMsgFrame::_messageEntries[0] 
		}; 
		
		AFX_COMDAT const AFX_MSGMAP_ENTRY CMsgFrame::_messageEntries[] = 
		{
			{ WM_PAINT, 0, 0, 0, AfxSig_lwl,(AFX_PMSG)(AFX_PMSGW)(LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM))&OnPaint },
			{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } 
		}; 

    2.3 代码说明
      2.3.1 _messageEntries[], 静态
        类型为 AFX_MSGMAP_ENTRY
    	  保存CMsgFrame中消息ID和对应的
    	  消息处理函数的数组
    	2.3.2 messageMap, 静态
    	  类型为 AFX_MSGMAP
 		    保存了CMsgFrame中的_GetBaseMessageMap
		    函数指针以及_messageEntries数组地址
   	  2.3.3 _GetBaseMessageMap, 静态
   	    获取父类的messageMap的地址
   	  2.3.4 GetMessageMap,虚函数
        获取自己的messageMap地址
    2.4 代码关系
      CMsgFrame::GetMessageMap -〉&messageMap{
      &_messageEntries[0] -> { ID<->Func, 
                               ID<->Func, 
                               .... 
                             }
		  _GetBaseMessageMap -> &parent::messageMap 
		                        { &_messageEntries[0],
		                           _GetBaseMessageMap->&parent::messageMap
		                        }
			}
  
  3 消息映射过程
    3.1 消息处理函数WindowProc收到消息后, 
        调用OnWndMsg处理消息,OnWndMsg如果不
        处理消息,那么WindowProc将调用
        DefWindowProc默认处理消息并返回.
    3.2 OnWndMsg处理消息
    	3.2.1 使用GetMessageMap函数获取该
    	  窗口类的messageMap变量的地址.
	  		const AFX_MSGMAP* pMessageMap; 
	  		pMessageMap = GetMessageMap();
	    3.2.2 在messageMap中的lpEntries数组
	      中,查找消息ID所对应的数组元素.
	    3.2.3 如果未找到,获取父类的messageMap
	      指针,返回3.2.2,从父类的lpEntries
	      数组继续查找.
	    3.2.4 如果找到,获取找到的数组元素的
	      地址lpEntry,退出查找过程,执行下一步.
	      const AFX_MSGMAP_ENTRY* lpEntry = NULL;
				for ( ; 
		     pMessageMap != NULL;	
		     pMessageMap = (*pMessageMap->pfnGetBaseMap)())
				{
					lpEntry = AfxFindMessageEntry(
				  	pMessageMap->lpEntries,
						message, 0, 0))
					if( lpEntry != NULL )
					{
						goto LDispatch;
					}
				}
	    3.2.5 根据找到的lpEntry的nSig标识,
	      调用lpEntry当中的pfn函数指针,处理
	      消息.
				LDispatch:
					union MessageMapFunctions mmf;
					mmf.pfn = lpEntry->pfn;
				  int nSig;
				  nSig = lpEntry->nSig;
				  switch (nSig)
				  {
					case AfxSig_lwl:
						lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
						break;
					}
					
二 MFC的消息分类

  1 窗口消息 
    例如WM_CREATE、WM_PAINT、鼠标、键盘等
    消息,这些消息的处理方式是直接调用消息
    处理函数.
    这类消息使用的宏:
      ON_MESSAGE(  )
      ON_WM_XXXXX( ): ON_WM_CREATE()
    消息处理时,采用3.2的处理方式.
    
  2 命令消息 WM_COMMAND
    菜单、工具栏、按钮等点击时的命令. 消息
    首先发送到主窗口,由主窗口逐层向子窗口
    派发。
    这类的消息使用的宏:
       ON_COMMAND( )
       ON_COMMAND_RANGE( )
    消息处理时,在OnWndMsg中调用OnCommand
    处理函数进行消息处理.
       
  3 通知消息 WM_NOTIFY
    子窗口对父窗口的通知消息。
      控件消息宏,
      例如: EDIT控件 ON_EN_CHANGE
      ON_NOTIFY/ON_NOTIFY_RANGE
    消息处理时,在OnWndMsg中调用OnNotify
    (OnCommand)处理函数进行消息处理
    
	4 自注册消息
	  用户自注册消息的处理。用户需调用
	  RegisterWindowMessage函数注册消息,然后
	  在消息映射中使用.
	  UINT RegisterWindowMessage(
     LPCTSTR lpString //消息名字符串
    );
    返回注册成功的消息ID(0xC000-0xFFFF)
	  消息映射宏: ON_REGISTERED_MESSAGE
	  消息处理时, 与窗口消息处理类似,但是
	  在查找消息处理函数和执行消息处理函数
	  时不同.
	  
三 MFC菜单
  1 MFC菜单相关类
    CMenu类 - 封装HMENU句柄,及相关的菜单的
              API函数.
  2 菜单的用法
    2.1 菜单资源的添加
    2.2 创建时,在窗口中添加菜单
    2.3 菜单项的命令相应ON_COMMAND
    
  3 注意:
    只有是继承CCmdTarget的子类,都可以添加
    消息映射机制.